package com.ziq.base.service

import java.nio.ByteBuffer

class MessageProto {

    companion object {

        const val OpAuth = 7
        const val OpRaw = 9

        const val rawHeaderLen = 16
        // size
        const val packSize      = 4
        const val headerSize    = 2
        const val verSize       = 2
        const val opSize        = 4
        const val seqSize       = 4
        const val rawHeaderSize = packSize + headerSize + verSize + opSize + seqSize

        // offset
        const val packOffset   = 0
        const val headerOffset = packOffset + packSize
        const val verOffset    = headerOffset + headerSize
        const val opOffset     = verOffset + verSize
        const val seqOffset    = opOffset + opSize

        const val bodyOffset  = seqOffset + seqSize

        fun intToByteArray4(num: Int): ByteArray {
            val byteArray = ByteArray(4)
            val highH = ((num shr 24) and 0xff).toByte()
            val highL = ((num shr 16) and 0xff).toByte()
            val LowH = ((num shr 8) and 0xff).toByte()
            val LowL = (num and 0xff).toByte()
            byteArray[0] = highH
            byteArray[1] = highL
            byteArray[2] = LowH
            byteArray[3] = LowL
            return byteArray
        }

        fun intToByteArray2(num: Int): ByteArray {
            val byteArray = ByteArray(2)
            val LowH = ((num shr 8) and 0xff).toByte()
            val LowL = (num and 0xff).toByte()
            byteArray[0] = LowH
            byteArray[1] = LowL
            return byteArray
        }

        fun replaceByteArray(target : ByteArray, replacePart : ByteArray, startIndex : Int){
            if(target.isNotEmpty() && replacePart.isNotEmpty()){
                val endIndex = startIndex + (replacePart.size - 1)
                if(startIndex >= 0 && endIndex <= (target.size - 1)){
                    for ((index, byte) in replacePart.withIndex()){
                        target[startIndex + index] = byte
                    }
                }
            }
        }
    }

    var version : Int = 0
    var op : Int = 0
    var seq : Int = 0
    var body : ByteArray? = null


    @Throws(Exception::class)
    fun parseData(bytes: ByteArray) {
        if(bytes.size < rawHeaderSize){
            throw Exception("ByteArray data size is wrong!")
        }
        val packLen = ByteBuffer.wrap(bytes.copyOfRange(packOffset, headerOffset)).int
        //四字节读一个int
        val headerLen = ByteBuffer.wrap(ByteArray(2) + bytes.copyOfRange(headerOffset, verOffset)).int
        version = ByteBuffer.wrap(ByteArray(2) + bytes.copyOfRange(verOffset, opOffset)).int
        op = ByteBuffer.wrap(bytes.copyOfRange(opOffset, seqOffset)).int
        seq = ByteBuffer.wrap(bytes.copyOfRange(seqOffset, bodyOffset)).int
        if (headerLen != rawHeaderSize) {
            throw Exception("headerLen is wrong!")
        }

        if(packLen > headerLen){
            body = bytes.copyOfRange(bodyOffset, packLen)
        } else {
            body = null
        }
    }

    fun getProtoByteArray() : ByteArray{
        val headerByteArray = ByteArray(rawHeaderLen)
        replaceByteArray(headerByteArray, intToByteArray4(rawHeaderLen + (body?.size?:0)), packOffset)
        replaceByteArray(headerByteArray, intToByteArray2(rawHeaderLen), headerOffset)
        replaceByteArray(headerByteArray, intToByteArray2(version), verOffset)
        replaceByteArray(headerByteArray, intToByteArray4(op), opOffset)
        replaceByteArray(headerByteArray, intToByteArray4(seq), seqOffset)
        return headerByteArray + (body?:ByteArray(0))
    }
}